#include<algorithm>
#include<stdint.h>
#include<functional>
#include<vector>
#include<iostream>
#include<memory>
#include<unordered_map>
#include<unistd.h>
using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;

class TimeTask{
private:
    uint64_t _id; // 任务ID
    uint32_t _timeout; // 超时时间
    bool _canceled; // 判断任务是否被取消
    TaskFunc _task;// 具体任务
    ReleaseFunc _releace;
public:
    TimeTask(uint64_t id,uint32_t timeout,const TaskFunc &cb):
    _id(id),
    _timeout(timeout),
    _canceled(false),
    _task(cb)
    {}
    ~TimeTask(){
        if(_canceled == false)
            _task(); _releace();
    }
    void SetRelease(const ReleaseFunc &cb){_releace = cb;}
    uint32_t GetTimeout(){return _timeout;}
    void cancel(){
        _canceled = true;
    }
};

using PtrTask = std::shared_ptr<TimeTask>;
using WeakTask = std::weak_ptr<TimeTask>;
 
//时间轮
class TimerWheel{
private:
    std::vector<std::vector<PtrTask>> _Wheel;
    int _capacity; //容量
    int _tick; // 秒
    std::unordered_map<uint64_t,WeakTask> _times;

    void RemoveTimer(uint64_t id){
        auto it = _times.find(id);
        if(it != _times.end())
            _times.erase(it);
    }
public:
    TimerWheel():
    _capacity(60),
    _tick(0),
    _Wheel(_capacity)
    {}
    //添加任务
    void TimeAdd(uint64_t id,uint32_t timeout,const TaskFunc &cb)
    {
        PtrTask pt(new TimeTask(id,timeout,cb));
        pt->SetRelease(std::bind(&TimerWheel::RemoveTimer,this,id));
        int pos = (_tick + timeout) %_capacity;
        _Wheel[pos].push_back(pt); 
        _times[id] = WeakTask(pt);
    }
    //刷新/延时
    void TimeRefresh(uint64_t id)
    {
        auto it = _times.find(id);
        if(it == _times.end())
            return; 
        PtrTask pt = it->second.lock();
        int delay = pt->GetTimeout();
        int pos = (_tick + delay) %_capacity;
        _Wheel[pos].push_back(pt); 
    }
    //每秒执行一次
    void RunTimeTask(){
        _tick = (_tick + 1) % _capacity;
        _Wheel[_tick].clear();
    }
    void TimerCancel(uint64_t id){
        auto it = _times.find(id);
        if(it == _times.end())
            return;
        PtrTask pt = it->second.lock();
        if(pt)
            pt->cancel(); 
    }
};
class Test{
public:
    Test(){
        std::cout<<"Tesk"<<std::endl;
    }
    ~Test(){
        std::cout<<"~Tesk"<<std::endl;
    }
};

void DelTest(Test *t){
    delete t;
}
int main(){
    TimerWheel tw;
    Test *t = new Test();
    tw.TimeAdd(888,5,std::bind(DelTest,t));
    for(int i = 0;i < 5;i++){
        sleep(1);
        tw.TimeRefresh(888);
        tw.RunTimeTask();
        std::cout<<"刷新\n";
    }
    tw.TimerCancel(888);
    while(1){
        sleep(1);
        std::cout<<"---------------\n";
        tw.RunTimeTask();
    }
    return 0;
}